package org.opens.netty.util;

import cn.hutool.core.lang.Assert;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;

/**
 * @author qiaoxuan
 * @date 2023/4/9 13:06
 */
public class ByteUtil {

    // 补零长度单位: Byte
    public static final int B = 0;
    // 补零长度单位: Bit
    public static final int BIT = 1;


    public static String bytes2HexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            stringBuilder.append(hex.toUpperCase() + " ");
        }
        return stringBuilder.toString();
    }

    /**
     * long类型  转 byte[] 高字节在前（高字节序） 根据length决定长度
     */
    public static byte[] long2Byte(long value, int length) {
        byte[] b = new byte[length];
        for (int i = 0; i < length; i++) {
            b[i] = (byte) (value >> (length - 1 - i) * 8 & 0xff);
        }
        return b;
    }

    public static String long2HexString(long value, int length) {
        byte[] bytes = long2Byte(value, length);
        String hexString = ByteUtil.bytes2HexString(bytes);
        return hexString.replaceAll(" ", "");
    }

    public static String byteBuf2HexString(ByteBuf byteBuf) {
        return bytes2HexString(ByteBufUtil.getBytes(byteBuf));
    }


    /**
     * hex字符串转byte数组
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte数组结果
     */
    public static byte[] hexToByteArray(String inHex) {
        int hexlen = inHex.length();
        byte[] result;
        if (hexlen % 2 == 1) {
            //奇数
            hexlen++;
            result = new byte[(hexlen / 2)];
            inHex = "0" + inHex;
        } else {
            //偶数
            result = new byte[(hexlen / 2)];
        }
        int j = 0;
        for (int i = 0; i < hexlen; i += 2) {
            result[j] = hexToByte(inHex.substring(i, i + 2));
            j++;
        }
        return result;
    }

    /**
     * Hex字符串转byte
     *
     * @param inHex 待转换的Hex字符串
     * @return 转换后的byte
     */
    private static byte hexToByte(String inHex) {
        return (byte) Integer.parseInt(inHex, 16);
    }

    /**
     * 将16进制字符串转换为byte数组
     * 例如"7F7F"->[127, 127], 可以发现, 4位字符串转换为byte数组后变为了2个长度的数组, 是因为一个byte占用8bit, 而一个16进制数占4bit, 所
     * 以两个16进制数对应1个byte, 因此长度除以2
     * 注意:
     * - 传入的字符串如果不是偶数位的会在前面补0
     *
     * @param hex 待转换的16进制字符串
     * @return byte数组
     */
    public static byte[] hexStringToByteArray(String hex) {
        // 如果长度为奇数, 则在前面补0
        hex = hex.length() % 2 == 1 ? "0" + hex : hex;

        int len = hex.length();

        // 思考16进制与byte所占用bit的长度即可换算
        // 注意: 16进制数总是双位的, 例如不会出现单独的F, 而是0F
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            // 因为一个byte占用8bit, 而一个16进制数占4bit, 所以两个16进制数对应1个byte, 因此长度除以2
            data[i / 2] = (byte) ((Character.digit(hex.charAt(i), 16) << 4)
                    + Character.digit(hex.charAt(i + 1), 16));
        }

        return data;
    }

    /**
     * 功能: 将byte数组转换为16进制字符串
     *
     * @param b 待转换的byte数组
     * @return 对应的16进制数
     */
    public static String byteArrayToHexString(byte[] b) {
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < b.length; i++) {
            String hex = Integer.toHexString(b[i] & 0xFF);
            // 对小于A的数补0
            if (hex.length() == 1) {
                hex = '0' + hex;
            }
            stringBuilder.append(hex.toUpperCase());
        }
        return stringBuilder.toString();
    }

    /**
     * 将byte数转换为16进制字符串
     *
     * @param b 待转换的byte数
     * @return 转换后得16进制数
     */
    public static String byteToHexString(byte b) {
        // & 0xFF 会将负数前面的1全部去掉, 因为byte负数前面所补的1都是无效的
        return Integer.toHexString(b & 0xFF).toUpperCase();
    }

    /**
     * 将16进制数转为byte数
     *
     * @param hex 待转换的16进制数
     * @return 转换后得byte数
     */
    public static byte hexStringToByte(String hex) {
        return Byte.valueOf(hex, 16);
    }

    /**
     * 功能: 将int数转换为16进制数
     *
     * @param num 待转换的int数
     * @return 转换后的16进制数
     */
    public static String intToHexString(int num) {
        return Integer.toHexString(num).toUpperCase();
    }

    /**
     * 功能: short类型转换为byte数组
     *
     * @param value 待转换的值
     * @return 转换后得byte数组
     */
    public static byte[] intToByteArray(int value) {
        return hexStringToByteArray(intToHexString(value));
    }

    /**
     * 功能: 将16进制数转换为int数
     *
     * @param hex 待转换的16进制数
     * @return 转换后的int数
     */
    public static int hexStringToInt(String hex) {
        return Integer.valueOf(hex, 16);
    }

    /**
     * 功能: long数转换为16进制数
     *
     * @param value long数
     * @return 转换后得16进制数
     */
    public static String longToHexString(long value) {
        return Long.toHexString(value).toUpperCase();
    }

    /**
     * 功能: long类型转换为byte数组
     *
     * @param value 待转换的值
     * @return 转换后得byte数组
     */
    public static byte[] longToByteArray(long value) {
        return hexStringToByteArray(longToHexString(value));
    }

    /**
     * 功能: 将16进制数转换为long数
     *
     * @param hex 待转换的16进制数
     * @return 转换后的long数
     */
    public static long hexStringToLong(String hex) {
        return Long.valueOf(hex, 16);
    }

    /**
     * 功能: short数转16进制字符串
     *
     * @param value short数
     * @return 转换后得16进制字符串
     */
    public static String shortToHexString(short value) {
        return Integer.toHexString(value).toUpperCase();
    }


    /**
     * 功能: short类型转换为byte数组
     *
     * @param value 待转换的值
     * @return 转换后得byte数组
     */
    public static byte[] shortToByteArray(short value) {
        return hexStringToByteArray(shortToHexString(value));
    }

    /**
     * 将16进制数转为short数
     *
     * @param hex 待转换的16进制数
     * @return 转换后得short数
     */
    public static short hexStringToShort(String hex) {
        return Short.valueOf(hex, 16);
    }

    /**
     * 将2进制字符串转换为16进制字符串
     * 备注:
     * - 无法转换负数的2进制字符串, Integer.valueOf只能转换无符号数
     * @param binaryString  2进制字符串
     * @return  16进制字符串
     */
    public static String binaryStringToHexString(String binaryString) {
        return intToHexString(Integer.valueOf(binaryString, 2));
    }

    /**
     * 将16禁止字符串转换为二进制字符串
     * @param hexString 待转换16进制字符串
     * @return  转换后得2进制字符串
     */
    public static String hexStringToBinaryString(String hexString) {
        return Integer.toBinaryString(hexStringToInt(hexString));
    }

    /**
     * 功能: 对无符号16进制字符串进行补全
     * @param hexString 无符号16进制字符串
     * @param fillLen   补全后得长度
     * @return  补全后得16进制字符串
     */
    public static String unsignedHexStringZeroFill(String hexString, int fillLen) {
        if (hexString.length() >= fillLen) {
            return hexString;
        }
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < fillLen - hexString.length(); i++) {
            sb.append("0");
        }
        sb.append(hexString);
        return sb.toString();
    }

    /**
     * 根据Byte或者Bit来补零16进制数
     * @param hexString 待补零的16进制数
     * @param fillLen   补零长度
     * @param unit      补零单位
     * @return  补零后得16进制字符串
     */
    public static String unsignedHexStringZeroFill(String hexString, int fillLen, int unit) {
        int realFillLen = 0;
        if (unit == B) {
            realFillLen = fillLen * 2;
        } else if (unit == BIT) {
            realFillLen = (fillLen / 4) + (fillLen % 4 == 0 ? 0 : 1);
        } else {
            throw new IllegalArgumentException("参数错误!");
        }
        return unsignedHexStringZeroFill(hexString, realFillLen);
    }

    /**
     * 对16进制字符串根据Byte进行切割
     * @param hexString 切割字符串
     * @param start 开始byte
     * @param end   结束byte
     * @return  切割后得字符串
     */
    public static String hexStringSubstringByByte(String hexString, int start, int end) {
        return hexString.substring(start * 2, end * 2);
    }

    /**
     * 将16进制字符串转换为带符号int; 认定最高位为符号位
     * @param hexString 16进制数
     * @return  带符号的int数
     */
    public static long hexStringToSignedInt(String hexString) {
        int len = 32 - hexString.length() * 4;
        return Long.valueOf(hexString, 16) << len >> len;
    }

    private static final String[] hexIndexToBinaryStringArray = new String[] {
            "0000",
            "0001",
            "0010",
            "0011",
            "0100",
            "0101",
            "0110",
            "0111",
            "1000",
            "1001",
            "1010",
            "1011",
            "1100",
            "1101",
            "1110",
            "1111"
    };

    /**
     * 将16进制字符串转换为2禁止字符串
     * @param hexString 16进制字符串
     */
    public static String hexStringToBinaryStringFixedLength(String hexString) {
        String[] hexArr = hexString.split("");
        StringBuilder builder = new StringBuilder();
        for (String item : hexArr) {
            builder.append(hexIndexToBinaryStringArray[Integer.valueOf(item, 16)]);
        }
        return builder.toString();
    }

    public static String toLongBinaryStringToHexString(String binaryString) {
        Assert.notBlank(binaryString, "参数不能为空!");

        // 自动补齐
        int binaryStringLength = binaryString.length() % 4;
        String _binaryString = binaryString;
        if (binaryStringLength != 0) {
            String prefix = "";
            for (int i = 0; i < 4 - binaryStringLength; i++) {
                prefix += "0";
            }
            _binaryString = prefix + _binaryString;
        }

        // 转换为16进制字符串
        StringBuilder builder = new StringBuilder();
        for (int i = 0; i < _binaryString.length(); i += 4) {
            String substring = _binaryString.substring(i, i + 4);
            builder.append(Integer.toHexString(Integer.valueOf(substring, 2)).toUpperCase());
        }

        return builder.toString();
    }

    /**
     * 浮点数转16进制字符串
     * - 转换后的结果为4字节
     * @param val   待转换的浮点数
     * @return  转换后得16进制字符串
     */
    public static String floatToHex(float val) {
        return Integer.toHexString(Float.floatToIntBits(val));
    }

    /**
     * 将16进制字符串转换为float
     * @param hex   待转换的16进制字符串
     * @return  转换结果
     */
    public static float hexToFloat(String hex) {
        Long l = Long.parseLong(hex, 16);
        return Float.intBitsToFloat(l.intValue());
    }

}
